package com.gin.supermarket_inventory_system.inventory.controller;

import com.gin.common.constant.ApiPath;
import com.gin.common.utils.StrUtils;
import com.gin.database.base.BaseFields;
import com.gin.database.validation.EntityId;
import com.gin.database.vo.response.ResPage;
import com.gin.security.Constant.Security;
import com.gin.spring.annotation.MyRestController;
import com.gin.spring.exception.BusinessException;
import com.gin.spring.vo.response.Res;
import com.gin.supermarket_inventory_system.commodity.dto.vo.CommodityVo;
import com.gin.supermarket_inventory_system.commodity.service.CommodityQueryService;
import com.gin.supermarket_inventory_system.inventory.docket.InventoryDocket;
import com.gin.supermarket_inventory_system.inventory.dto.form.InventoryAddForm;
import com.gin.supermarket_inventory_system.inventory.dto.form.InventoryUpdateForm;
import com.gin.supermarket_inventory_system.inventory.dto.param.InventoryPageParam;
import com.gin.supermarket_inventory_system.inventory.dto.vo.InventoryVo;
import com.gin.supermarket_inventory_system.inventory.entity.InventoryPo;
import com.gin.supermarket_inventory_system.inventory.entity.InventoryReceiptDetailPo;
import com.gin.supermarket_inventory_system.inventory.enums.InventoryReceiptType;
import com.gin.supermarket_inventory_system.inventory.service.InventoryReceiptDetailService;
import com.gin.supermarket_inventory_system.inventory.service.InventoryService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;
import java.util.stream.Collectors;

/**
 *
 * @since : 2023/9/26 16:37
 * @author : ginstone
 * @version : v1.0.0
 **/
@Slf4j
@MyRestController(InventoryController.API_PREFIX)
@Tag(name = InventoryController.GROUP_NAME)
@RequiredArgsConstructor
public class InventoryController {
    /**
     *  接口路径前缀
     */
    public static final String API_PREFIX = InventoryDocket.API_PREFIX + "/info";
    /**
     *  接口文档分组名称
     */
    public static final String GROUP_NAME = "库存信息管理";
    /**
     * 本接口使用的主Service类
     */
    private final InventoryService service;
    private final CommodityQueryService commodityQueryService;
    private final InventoryReceiptDetailService detailService;

    @PostMapping(ApiPath.ADD)
    @Operation(summary = "添加")
    @PreAuthorize(Security.PRE_AUTHORITY_URI_OR_ADMIN)
    public Res<Void> postAdd(
            @RequestBody @Validated InventoryAddForm form,
            @SuppressWarnings("unused") HttpServletRequest request
    ) {
        service.save(form.toPo());
        return Res.success();
    }

    @PostMapping(ApiPath.UPDATE)
    @Operation(summary = "修改")
    @PreAuthorize(Security.PRE_AUTHORITY_URI_OR_ADMIN)
    public Res<Void> postUpdate(
            @RequestBody @Validated InventoryUpdateForm form,
            @SuppressWarnings("unused") HttpServletRequest request
    ) {
        service.updateById(form.toPo());
        return Res.success();
    }

    @PostMapping(ApiPath.DEL)
    @Operation(summary = "删除")
    @PreAuthorize(Security.PRE_AUTHORITY_URI_OR_ADMIN)
    public Res<Void> postDel(
            @RequestParam @EntityId(service = InventoryService.class) Long id,
            @SuppressWarnings("unused") HttpServletRequest request
    ) {
        // 有库存单据的库存禁止删除
        final long count = detailService.countByInventoryId(id);
        if (count > 0) {
            throw BusinessException.of(HttpStatus.BAD_REQUEST, String.format("该库存有 %d 条库存单据, 禁止删除", count));
        }

        service.removeById(id);
        return Res.success("删除成功");
    }


    @GetMapping("search")
    @Operation(summary = "搜索库存", description = "根据给出的文本搜索库存")
    @PreAuthorize(Security.PRE_AUTHORITY_URI_OR_ADMIN)
    public Res<List<InventoryVo>> getSearch(String keyword, @SuppressWarnings("unused") HttpServletRequest request) {
        // 如果为纯数字，按条码搜索
        if (StrUtils.isNumber(keyword)) {
            final List<InventoryPo> inventories = service.listByBarcode(keyword);
            if (inventories.isEmpty()) {
                throw BusinessException.of(HttpStatus.BAD_REQUEST, "没有查找到符合条件的库存");
            }
            final List<InventoryVo> data = inventories.stream().map(InventoryVo::new).toList();
            fillCommodityInfo(data);
            return Res.of(data);
        }

        //todo 其他搜索逻辑

        return null;
    }

    @GetMapping(ApiPath.PAGE)
    @Operation(summary = "分页查询")
    @PreAuthorize(Security.PRE_AUTHORITY_URI_OR_ADMIN)
    public ResPage<InventoryVo> getPage(@ParameterObject InventoryPageParam param
            , @SuppressWarnings("unused") HttpServletRequest request) {
        final ResPage<InventoryVo> pageData = service.pageByParam(param, InventoryVo::new);

        final List<InventoryVo> data = pageData.getData();

        if (data.isEmpty()) {
            throw BusinessException.of(HttpStatus.BAD_REQUEST, "未找到数据");
        }

        fillCommodityInfo(data);
        return pageData;
    }

    private void fillCommodityInfo(List<InventoryVo> data) {
        // 商品信息
        final List<CommodityVo> commodity = commodityQueryService.listByIds(data.stream().map(InventoryVo::getCommodityId).collect(Collectors.toSet()));

        // 单据详情
        final List<InventoryReceiptDetailPo> details = detailService.listByInventoryId(InventoryReceiptType.PURCHASE, data.stream().map(BaseFields::getId).collect(Collectors.toSet()));


        for (InventoryVo item : data) {
            // 填充商品信息
            commodity.stream().filter(i -> item.getCommodityId() == i.getId()).findFirst().ifPresent(c -> item.setCommodity(c.clone()));

            // 填充上次进货价
            details.stream().filter(i -> i.getInventoryId() == item.getId()).min((o1, o2) -> Math.toIntExact(o2.getId() - o1.getId())).ifPresent(i -> item.setLastPurchasePrice(Math.abs(i.getPrice())));
        }
    }


}